﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using System.Data.SqlClient;
using SiGeSIB.Data.Common;

namespace SiGeSIB.GUI.Common
{
	public class FormController
	{
		public FormController(DefaultStatusBar statusBar)
		{
			_StatusBar = statusBar;
			_InitialStatusMessage = statusBar.Message;
			_ErrorLabels = new Dictionary<string, Control[]>();
			_FieldsToLock = new List<object>();
		}

		#region Attributes
		private int _BusyCount = 0;
		private Dictionary<string, Control[]> _ErrorLabels;
		private string _InitialStatusMessage;
		private DefaultStatusBar _StatusBar;
		private Color DefaultColor = Color.Black;
		private Color ErrorColor = Color.Red;
		private List<object> _FieldsToLock;
		private bool _IsLocked;
		#endregion

		#region Events
		public event EventHandler BusyStateChanged;
		#endregion

		#region Properties
		public bool IsBusy { get { return _BusyCount > 0; } }
		public bool IsLocked 
		{
			get 
			{
				return IsBusy || _IsLocked; 
			}
			set
			{
				if (value != _IsLocked)
				{
					if (_IsLocked == IsLocked)
						_ChangeLockState();
					_IsLocked = value;
				}
			}
		}
		public List<object> FieldsToLock
		{
			get { return _FieldsToLock; }
			set { _FieldsToLock = value; }
		}
		#endregion

		#region Methods
		#region Busy
		private void OnBusyStateChanged()
		{
			_ChangeLockState();

			if (BusyStateChanged != null)
				BusyStateChanged(this, new EventArgs());
		}
		public void EnableBusy()
		{
			EnableBusy(null);
		}

		public void EnableBusy(string msg)
		{
			_BusyCount++;

			// Se passou uma mensagem, altera.
			if (!string.IsNullOrEmpty(msg))
				_StatusBar.Message = msg;

			// Se ficou busy agora
			if (_BusyCount == 1)
				OnBusyStateChanged();
		}
		public void DisableBusy()
		{
			_BusyCount = Math.Max(0, _BusyCount - 1);

			// Se deixou de ficar busy
			if (_BusyCount == 0)
				OnBusyStateChanged();
		} 
		#endregion
		#region FieldsLocking
		private void _ChangeLockState()
		{
			foreach (object control in _FieldsToLock)
			{
				if (control is ToolStripItem)
					((ToolStripItem)control).Enabled = !IsLocked;
				else if (control is TextBoxBase)
					((TextBoxBase)control).ReadOnly = IsLocked;
				else if (control is UAddressControl)
					((UAddressControl)control).ReadOnly = IsLocked;
				else if (control is Control)
					((Control)control).Enabled = !IsLocked;
			}
		}
		#endregion

		private void _LoadInnerException(Exception ex)
		{
			_StatusBar.Message = ex.Message;

			if (ex is ValidationError)
			{
				ValidationError error = ex as ValidationError;
				Control[] controls = null;

				if (_ErrorLabels.ContainsKey(error.FieldName))
				{
					controls = _ErrorLabels[error.FieldName];
				}
				else
				{
					Control control = error.InvalidControl as Control;
					if (control != null)
						controls = new Control[] { control };
				}

				if (controls != null)
					foreach (Control control in controls)
					{
						control.ForeColor = ErrorColor;
						control.Click += new EventHandler((sender, args) => _StatusBar.Message = ex.Message);
					}
			}
			else if (ex is ExceptionsContainer)
			{
				foreach (Exception e in (ExceptionsContainer)ex)
					_LoadInnerException(e);
			}
			else if (ex is SqlException)
			{
				_StatusBar.Message = "Erro na conexão com o banco de dados.";
			}
		}

		public void LoadError(Exception ex)
		{
			_InitialStatusMessage = _StatusBar.Message;
			_StatusBar.SetIcon(DefaultStatusBar.EStatusImage.Error);
			_StatusBar.SetForeground(ErrorColor);

			_LoadInnerException(ex);
		}
		public void ClearErrors()
		{
			_StatusBar.Message = _InitialStatusMessage;
			_StatusBar.SetIcon(DefaultStatusBar.EStatusImage.Info);
			_StatusBar.SetForeground(DefaultColor);

			foreach (Control[] controls in _ErrorLabels.Values)
			{
				if (controls != null)
					foreach (Control control in controls)
						control.ForeColor = DefaultColor;
			}
		}

		public void AddErrorLabel(string fieldName, Control[] controls)
		{
			if (!_ErrorLabels.ContainsKey(fieldName))
				_ErrorLabels.Add(fieldName, controls);
			else
				_ErrorLabels[fieldName] = controls;
		}
		public void DisplayIdleMessage(string message)
		{
			_StatusBar.Message = message;
		}
		#endregion
	}
}
